﻿// -------------------------------------------------------------------------
//    @FileName         :    NFBagPageOpMgrInterface.h
//    @Author           :    Gao.Yi
//    @Date             :    2025-10-21
//    @Email			:    445267987@qq.com
//    @Module           :    NFBagPageOpMgrInterface
//    @Desc             :
//
// -------------------------------------------------------------------------

// --- 文件总结 ---------------------------------------------------------------
// 本文件定义了背包页签操作管理抽象类 `NFBagPageOpMgrInterface`，用于统一封装
// 物品在“背包页签”上的增删查移动等高阶操作（跨页签、批量、尽量/必须模式、
// 绑定/过期限制、金币类物品直通货币接口等），并对提交语义（需 Commit 生效）、
// 嵌套创建防护、错误码聚合（页签满）等行为进行集中处理。
//
// 关键职责：
// - 路由到合适页签并执行添加/删除（含批量、可尽量添加/删除，或必须全部成功）
// - 金币/货币类物品透传至资金接口（IncMoney/DecMoney）
// - 支持根据物品/原因自动计算目标页签，或显式指定页签
// - 删除时支持按 UUID/按格子/按一批 ItemOpData 删除，并支持绑定过滤、过期过滤
// - 记录操作物品与最终变更结果，便于外层统一同步与统计
// - 提供遍历已添加的页签操作器、物品查找（按 UUID）等工具函数
//
// 使用要点：
// - 构造时可指定是否需要提交（bNeedCommit）；若需要提交，则禁止在嵌套上下文中二次创建
// - 非货币类物品添加前会调用 AddItemFix 修正属性（如绑定、品质）
// - 变更仅在 Commit() 后写入实际容器；外部需实现 Commit 与资金相关接口
// ---------------------------------------------------------------------------

#pragma once

#include <unordered_map>
#include "NFBagBaseOp.h"
#include "NFBagPageOpDefine.h"

class NFBagPage;
class NFBagPageOp;
class NFGridItem;
class NFBagPageInterface;
class NFBagPageInterfacePackage;

class NFBagPageOpMgrInterface : public NFBagBaseOp<NFBagPageOpMgrInterface>
{
public:
    /**
     * @brief 构造操作管理器
     * @param ownerId 归属玩家/对象ID
     * @param iOpReason 本次操作原因（影响目标页签选择）
     * @param bNeedCommit 是否需要提交（需要时禁止嵌套创建，所有变更在 Commit 后生效）
     */
    NFBagPageOpMgrInterface(uint64_t ownerId, int iOpReason, bool bNeedCommit = false);
    ~NFBagPageOpMgrInterface() override;

public: /// 添加物品
    /**
     * @brief 自动选择合适页签添加物品（WillAddItemData 版本）
     * @param stWillAddItemData 物品基础数据（不含数量）
     * @param iNum 想要添加的数量（可超过叠加上限，内部拆分）
     * @param pAddedNum 输出实际添加数量（=nullptr 全部添加，!=nullptr 尽可能添加）
     * @return 0成功，非0失败
     */
    virtual int AddToBag(WillAddItemData& stWillAddItemData, int iNum, int* pAddedNum = nullptr);
    
    /**
     * @brief 自动选择合适页签添加物品（物品ID版本，货币透传 IncMoney）
     * @param iItemId 物品ID
     * @param iNum 要添加的数量
     * @param pAddedNum 输出实际添加数量（=nullptr 全部添加，!=nullptr 尽可能添加）
     * @return 0成功，非0失败
     */
    virtual int AddToBag(int iItemId, int iNum, int* pAddedNum = nullptr);

    /**
     * @brief 批量添加物品到合适的背包页签（逐项独立处理）
     * @param astWillAddItemData 物品数据列表
     * @param aiWantAddNum 每种物品对应的要添加的数量（可超过叠加数）
     * @param paiAddedNum 输出实际添加数量列表（=nullptr 全部添加，!=nullptr 尽可能添加）
     * @return 0成功，非0失败
     */
    virtual int AddToBag(std::vector<WillAddItemData>& astWillAddItemData, const std::vector<int>& aiWantAddNum, std::vector<int>* paiAddedNum = nullptr);
    
    /**
     * @brief 批量添加物品（带数量的物品数据）
     * @param astWillAddItemData 物品数据列表（含数量）
     * @param paiAddedNum 输出实际添加数量列表（=nullptr 全部添加，!=nullptr 尽可能添加）
     * @return 0成功，非0失败
     */
    virtual int AddToBag(std::vector<WillAddItemDataWithNum>& astWillAddItemData, std::vector<int>* paiAddedNum = nullptr);

    /**
     * @brief 使用现有物品对象添加（不改变传入对象数量）
     * @param stItem 物品对象
     * @param iNum 想要添加的数量（不可超过物品个数）
     * @param pAddedNum 输出实际添加数量（=nullptr 全部添加，!=nullptr 尽可能添加）
     * @return 0成功，非0失败
     * @note 操作完毕后不会修改stItem个数
     */
    virtual int AddToBag(NFGridItem& stItem, int iNum, int* pAddedNum = nullptr);

    /**
     * @brief 添加物品到指定背包页签（支持尽量添加）
     * @param stWillAddItemData 物品数据
     * @param iNum 要添加的数量（可超过叠加数）
     * @param iBagType 要添加到哪个背包页签（必须合法）
     * @param bAsPossible 是否尽可能添加（能添加多少添加多少）
     * @param pAddedNum 输出实际添加数量
     * @return 0成功，非0失败
     */
    virtual int AddToBagPage(WillAddItemData& stWillAddItemData, int iNum, int iBagType, bool bAsPossible, int* pAddedNum);
    
    /**
     * @brief 添加物品到指定背包页签
     * @param stWillAddItemData 物品数据
     * @param iNum 要添加的数量（可超过叠加数）
     * @param iBagType 要添加到哪个背包页签（必须合法）
     * @param pAddedNum 输出实际添加数量（=nullptr 全部添加，!=nullptr 尽可能添加）
     * @return 0成功，非0失败
     */
    virtual int AddToBagPage(WillAddItemData& stWillAddItemData, int iNum, int iBagType, int* pAddedNum = nullptr);

    /**
     * @brief 批量添加物品到指定背包页签
     * @param astWillAddItemData 物品数据列表
     * @param aiWantAddNum 每种物品对应的要添加的数量
     * @param iBagType 要添加到哪个背包页签（必须合法）
     * @param paiAddedNum 输出实际添加数量列表（=nullptr 全部添加，!=nullptr 尽可能添加）
     * @return 0成功，非0失败
     */
    virtual int AddToBagPage(std::vector<WillAddItemData>& astWillAddItemData, const std::vector<int>& aiWantAddNum, int iBagType, std::vector<int>* paiAddedNum = nullptr);

    /**
     * @brief 添加物品到指定背包页签（物品对象版本）
     * @param stItem 物品对象
     * @param iNum 想要添加的数量（不可超过物品个数）
     * @param iBagType 要添加到哪个背包页签（必须合法）
     * @param pAddedNum 输出实际添加数量（=nullptr 全部添加，!=nullptr 尽可能添加）
     * @return 0成功，非0失败
     * @note 操作完毕后不会修改stItem个数
     */
    virtual int AddToBagPage(NFGridItem& stItem, int iNum, int iBagType, int* pAddedNum = nullptr);

    /**
     * @brief 添加物品到合适的背包页签（支持尽量添加）
     * @param stWillAddItemData 物品数据
     * @param iNum 要添加的数量
     * @param bAsPossible 是否尽可能添加
     * @param pAddedNum 输出实际添加数量
     * @return 0成功，非0失败
     * @note 自动查找物品添加页签
     */
    virtual int AddToBag(WillAddItemData& stWillAddItemData, int iNum, bool bAsPossible, int* pAddedNum);
    
    /**
     * @brief 添加物品到合适的背包页签（物品ID版本，支持尽量添加）
     * @param iItemId 物品ID
     * @param iNum 要添加的数量
     * @param bAsPossible 是否尽可能添加
     * @param pAddedNum 输出实际添加数量
     * @return 0成功，非0失败
     */
    virtual int AddToBag(int iItemId, int iNum, bool bAsPossible, int* pAddedNum);
    
    /**
     * @brief 添加物品到指定背包页签（物品对象版本，支持尽量添加）
     * @param stItem 物品对象
     * @param iNum 想要添加的数量（不可超过物品个数）
     * @param iBagType 要添加到哪个背包页签（必须合法）
     * @param bAsPossible 是否尽可能添加（能添加多少添加多少）
     * @param pAddedNum 输出实际添加数量（!=nullptr时用来存放实际添加个数）
     * @return 0成功，非0失败
     */
    virtual int AddToBagPage(NFGridItem& stItem, int iNum, int iBagType, bool bAsPossible, int* pAddedNum);

    /**
     * @brief 自动页签添加，支持尽量添加（NFGridItem 版本）
     * @param stItem 物品对象
     * @param iNum 要添加的数量
     * @param bAsPossible 是否尽可能添加
     * @param pAddedNum 输出实际添加数量
     * @return 0成功，非0失败
     * @note 自动查找物品添加页签
     */
    virtual int AddToBag(NFGridItem& stItem, int iNum, bool bAsPossible, int* pAddedNum);

    /**
     * @brief 批量添加物品到合适的背包页签（支持尽量添加）
     * @param astWillAddItemData 物品数据列表
     * @param aiWantAddNum 每种物品对应的要添加的数量
     * @param bAsPossible 是否尽可能添加
     * @param paiAddedNum 输出实际添加数量列表
     * @return 0成功，非0失败
     */
    virtual int AddToBag(std::vector<WillAddItemData>& astWillAddItemData, const std::vector<int>& aiWantAddNum, bool bAsPossible, std::vector<int>* paiAddedNum);

    /**
     * @brief 添加一组简单物品（proto Item），返回未添加完的剩余项
     */
    virtual int AddItems(const std::vector<Item>& vecWares, bool bAsPossible = false, std::vector<Item>* pVecLeftWares = nullptr);
public: ///删除物品
    /**
     * @brief 从所有已添加的页签按顺序删除指定物品
     * @param iItemID 要删除的物品ID
     * @param iNum 要删除的数量（可超过堆叠数，删除多个槽）
     * @param piDelNum 输出实际删除数量（=nullptr 全部删除不够会返回错误码，!=nullptr 尽可能删除）
     * @return 0成功，非0失败
     * @note 按添加容器顺序依次遍历扣除，在各个容器中排序删除物品，可能从多个槽扣除
     */
    virtual int DelAllItems(int iItemID, int iNum, int* piDelNum = nullptr);
    
    /**
     * @brief 从已添加的页签删除指定物品
     * @param iItemID 要删除的物品ID
     * @param iNum 要删除的数量
     * @param piDelNum 输出实际删除数量（=nullptr 全部删除，!=nullptr 尽可能删除）
     * @return 0成功，非0失败
     */
    virtual int DelItems(int iItemID, int iNum, int* piDelNum = nullptr);
    
    /**
     * @brief 根据物品ID和UUID删除物品
     * @param iItemID 物品ID
     * @param ullItemUUid 物品UUID
     * @return 0成功，非0失败
     */
    virtual int DelItemsByUUid(int iItemID, uint64_t ullItemUUid);

    /**
     * @brief 从给定的容器中尽量删除物品
     * @param vecBagPageOp 容器列表
     * @param iItemID 要删除的物品ID
     * @param iWantDelNum 要删除的数量（可超过堆叠数）
     * @param iRealDelNum 输出实际删除数量
     * @return 0成功，非0失败
     * @note 按容器顺序依次遍历扣除，在各个容器中排序删除物品，可能从多个槽扣除
     */
    virtual int DelItems(const std::vector<NFBagPageOp*>& vecBagPageOp, int iItemID, int iWantDelNum, int& iRealDelNum);

    /**
     * @brief 删除一批物品
     * @param vecItemOpData 从这些物品中删除（resid必须一致，归属必须一致）
     * @param pSortFunc 物品排序函数（=nullptr 不排序）
     * @param iWantDelNum 想要删除的数量
     * @param piRealDelNum 输出实际删除数量（=nullptr 全部删除，!=nullptr 尽可能删除）
     * @param pbHadDelBind 输出是否删除了绑定物品（!=nullptr时使用）
     * @return 0成功，非0失败
     */
    /**
     * @brief 删除同类物品（可排序），支持返回是否删除过绑定物品
     */
    virtual int DelSameItems(std::vector<ItemOpData>& vecItemOpData, NFItemOpDataCompareFun pSortFunc, int iWantDelNum, int* piRealDelNum, bool* pbHadDelBind);

    // 删除物品
    // vecWareOpData 将从这些物品中按顺序删除
    // iCanDelNum 想要删除的个数
    // iRealDealNum 实际删除的个数
    virtual int DelSameItemsDel(const std::vector<ItemOpData>& vecItemOpData, int iCanDelNum, int& iRealDealNum, bool* pbHadDelBind);

    // 给输出参数设置初始值
    virtual void DelSameItemsOutInit(int* piRealDelNum, bool* pbHadDelBind);

    // 校验参数
    // vecWareOpData 将从这些物品中删除
    // ullOwnerRoleID 物品的归属，必须是自己或室友,且一致
    // iResID vecWareOpData里的物品，必须一致的
    // bNeedProc 后续删除逻辑是否要继续处理
    //  要删除的物品总数不够时，没必要处理
    virtual int DelSameItemsNeedProc(const std::vector<ItemOpData>& vecItemOpData, int iWantDelNum, int* piRealDelNum, bool& bNeedProc, uint64_t& ullOwnerRoleID, int& iItemID);


    /* 从指定的格子扣除物品
    iTabIndex 指定的页签
    iGridIndex 指定的格子
    iNum 扣除的数量
    */
    virtual int DelItemByGridIndex(int iBagType, int iGridIndex, int iNum);


    /* 删除所有背包页签中iResId一致的物品
    */
    virtual int DelAllItems(int iItemId);

    /* 从一批合适的背包页签扣除物品
        按物品类型获取合适的一批背包页签去删除
    piDelNum out
        = nullptr 全部删除
        != nullptr 尽可能删除，*piDelNum 存放实际删除个数
    */
    virtual int DelItems(const WillDelItemData& stWillDelWareData, int* piDelNum = nullptr);

    /* 从已添加的所有容器中，删除归属于自己的绑定物品
        iWantDelNum 想要要删除的个数
        piRealDelNum inout
            = nullptr 全部删除,不足时会返回物品不够的错误码
            != nullptr 尽可能删除,存放实际删除个数
    */
    virtual int DelBindItem(int iItemID, int iWantDelNum, int* piRealDelNum);

    /* 从已添加的所有容器中，查找指定uuid的物品
    ullUUID 物品的uuid
    pWareOut out 找到的物品指针
        可以直接修改此物品数据
        未找到时=nullptr(调用方需要判读)
        因为储物柜的存在，可能此物品并不归属自己(调用方需要判断)
    pWareContainerOp out 物品所属容器
        pWareOut !=null时，此值!=null
*/
    /**
     * @brief 按 UUID 查找可写物品与其所属页签操作器
     * @param ullUUID 物品UUID
     * @param pItemOut 输出物品指针（可直接修改）
     * @param pBagPageOp 输出物品所属页签操作器
     * @return 0成功，非0失败
     * @note 未找到时 pItemOut=nullptr；因储物柜存在，物品可能不归属自己
     */
    virtual int FindMutableItem(uint64_t ullUUID, NFGridItem*& pItemOut, NFBagPageOp*& pBagPageOp);

public:
    /**
     * @brief 遍历所有已添加的页签操作器
     * @param func 遍历回调函数
     *        - NFBagPageOp&: 页签操作器引用
     *        - bStop: 输出是否停止遍历（未设置时=false）
     * @return 0成功，非0失败
     */
    virtual int ForEachBagPageOp(const std::function<int(NFBagPageOp&, bool&)>& func);

public: /// 其它物品操作
    /**
     * @brief 跨页签交换两个格子物品（必须都存在）
     * @param iSrcBagType 源页签类型
     * @param iSrcGridIndex 源格子索引
     * @param iTargetBagType 目标页签类型
     * @param iTargetGridIndex 目标格子索引
     * @return 0成功，非0失败
     */
    virtual int SwapGrid(int iSrcBagType, int iSrcGridIndex, int iTargetBagType, int iTargetGridIndex);
    
    /**
     * @brief 将物品移动到其他背包页签
     * @param iBagTypeSrc 源页签类型
     * @param iGridIndexSrc 源格子索引
     * @param iBagTypeTarget 目标页签类型
     * @return 0成功，非0失败
     */
    virtual int MoveWare(int iBagTypeSrc, int iGridIndexSrc, int iBagTypeTarget);

public:
    /**
     * @brief 跨所有页签检测数量是否足够（提前短路）
     * @param iItemID 检测的物品ID
     * @param iNum 需要达到的个数
     * @param bEnough 输出是否足够
     * @return 0成功，非0失败
     * @note 物品个数够了立即返回，不用遍历所有物品，比GetItemNum快
     */
    virtual int HaveEnoughAllItem(int iItemID, int iNum, bool& bEnough);
    
    /**
     * @brief 检测物品数量是否足够
     * @param iItemID 检测的物品ID
     * @param iNum 需要达到的个数
     * @param bEnough 输出是否足够
     * @return 0成功，非0失败
     */
    virtual int HaveEnoughItem(int iItemID, int iNum, bool& bEnough);

    /**
     * @brief 顺序遍历之前添加的所有容器，获取物品总个数
     * @param iItemID 检测的物品ID
     * @param iItemNum 输出物品的总个数
     * @return 0成功，非0失败
     */
    virtual int GetAllItemNum(int iItemID, int& iItemNum);
    
    /**
     * @brief 获取物品总个数
     * @param iItemID 检测的物品ID
     * @param iItemNum 输出物品的总个数
     * @return 0成功，非0失败
     */
    virtual int GetItemNum(int iItemID, int& iItemNum);
public: /// 添加后续操作的物品容器
    /**
     * @brief 获取指定页签操作器，不存在则按需分配接口并创建操作器
     * @param iBagType 背包页签类型
     * @return 页签操作器指针（一定!=nullptr）
     */
    virtual NFBagPageOp* GetBagPageOpByBagType(int iBagType);
    
    /**
     * @brief 获取合适的背包页签容器来添加物品，未找到时分配添加一个
     * @param pItem 物品对象
     * @return 页签操作器指针（一定!=nullptr）
     */
    virtual NFBagPageOp* GetBagPageOpForAddToBagPage(const NFGridItem* pItem);
    
    /**
     * @brief 获取合适的背包页签容器来添加物品，未找到时分配添加一个
     * @param stWillAddItemData 待添加物品数据
     * @return 页签操作器指针（一定!=nullptr）
     */
    virtual NFBagPageOp* GetBagPageOpForAddToBagPage(const WillAddItemData& stWillAddItemData);

    /**
     * @brief 添加合适的背包页签
     * @param iItemID 物品ID
     * @return 0成功，非0失败
     */
    virtual int AddSuitableBagPage(int iItemID);
    
    /**
     * @brief 添加背包页签对应的容器
     * @param vecTabIndexs 页签索引列表
     * @return 0成功，非0失败
     */
    virtual int AddBagPageOp(const std::vector<int>& vecTabIndexs);

public:
    /**
     * @brief 设置删除时的过期截止时间（0 不校验；非0则不删过期<=该时间的物品）
     * @param dwUnixSec 过期时间戳（Unix秒）
     * @note 只影响后续删除操作：!=0时不删除已过期的物品（物品存在过期时刻 && 过期时刻<=此值）
     */
    virtual void SetDelExpireUnixSec(uint32_t dwUnixSec) { m_dwDelExpireUnixSec = dwUnixSec; }
    
    /**
     * @brief 获取删除时的过期截止时间
     * @return 过期时间戳（Unix秒）
     */
    virtual uint32_t GetDelExpireUnixSec() const { return m_dwDelExpireUnixSec; }

    /**
     * @brief 获取添加物品时的绑定策略
     * @return 绑定类型
     */
    virtual enItemBindType GetBindStatForAdd() const { return m_enBindStatForAdd; }
    
    /**
     * @brief 设置添加物品时的绑定策略
     * @param stat 绑定类型
     */
    virtual void SetBindStatForAdd(enItemBindType stat) { m_enBindStatForAdd = stat; }

    /**
     * @brief 设置背包操作原因
     * @param reason 操作原因
     */
    virtual void SetPackageOpReason(int reason) { m_enPackageOpReason = reason; }
    
    /**
     * @brief 获取背包操作原因
     * @return 操作原因
     */
    virtual int GetPackageOpReason() const { return m_enPackageOpReason; }

    /**
     * @brief 获取物品实际操作记录 <物品ID, 操作数量>
     * @return 操作记录映射（commit时记录操作过的物品，数量可以是任何数）
     */
    virtual const std::unordered_map<int, int>& GetOpItemRec() const { return m_opItemRec; }
    
    /**
     * @brief 获取物品实际变动记录 <物品ID, 变动数量>
     * @return 变动记录映射（只记录整个操作后变动了的物品数据，数量!=0）
     */
    virtual const std::unordered_map<int, int>& GetItemChangeRec() const { return m_itemChangeRec; }

    /**
     * @brief 获取所有者ID
     * @return 所有者ID
     */
    virtual uint64_t GetOwnerId() const { return m_ownerId; }
    
    /**
     * @brief 设置所有者ID
     * @param ownerId 所有者ID
     */
    virtual void SetOwnerId(uint64_t ownerId) { m_ownerId = ownerId; }

    /**
     * @brief 设置当页签满时是否禁止转流至"背包满处理"逻辑
     * @param bForbid true禁止，false允许
     */
    virtual void SetForbidAddWhenFull(bool bForbid) { m_bForbidAddWheFull = bForbid; }
    
    /**
     * @brief 获取当页签满时是否禁止转流至"背包满处理"逻辑
     * @return true禁止，false允许
     */
    virtual bool GetForbidAddWhenFull() const { return m_bForbidAddWheFull; }

public:
    /**
     * @brief 提交所有页签操作到真实容器（仅允许一次）并可选择是否同步客户端
     * @param bSyncToClient 是否将变更同步给客户端
     * @return 0成功，非0失败
     */
    virtual int Commit(bool bSyncToClient = true) = 0;
    
    /**
     * @brief 获取指定背包页签
     * @param iBagType 背包页签类型
     * @return 背包页签指针（可能为nullptr）
     */
    virtual NFBagPage* GetBagPage(int iBagType) = 0;
    
    /**
     * @brief 添加常用的随身容器
     * @return 0成功，非0失败
     */
    virtual int AddAllBagPage() = 0;
    
    /**
     * @brief 获取金钱数量
     * @param moneyType 金钱类型
     * @return 金钱数量
     */
    virtual int64_t GetMoneyNumber(int moneyType) = 0;
    
    /**
     * @brief 设置金钱数量
     * @param moneyType 金钱类型
     * @param num 金钱数量
     * @return 0成功，非0失败
     */
    virtual int SetMoneyNumber(int moneyType, int64_t num) = 0;
    
    /**
     * @brief 吐出物品（特殊处理）
     * @return 0成功，非0失败
     */
    virtual int Disgorgment() { return 0; };
    
    /**
     * @brief 增加金钱
     * @param enMoneyType 金钱类型
     * @param llMoney 想要增加的金钱数（must >= 0）
     * @param pAddedNum 输出实际增加数量（=nullptr 全部增加，!=nullptr 尽可能增加）
     * @return 0成功，非0失败
     * @note 即使增加的数量和llMoney不一致，也算成功
     */
    virtual int IncMoney(int enMoneyType, int llMoney, int* pAddedNum = nullptr) = 0;
    
    /**
     * @brief 减少金钱
     * @param enMoneyType 金钱类型
     * @param llMoney 想要减少的金钱数（must >= 0）
     * @param piDelNum 输出实际减少数量（=nullptr 全部减少，!=nullptr 尽可能减少）
     * @return 0成功，非0失败
     */
    virtual int DecMoney(int enMoneyType, int llMoney, int* piDelNum = nullptr) = 0;

    /**
     * @brief 背包满时添加物品的特殊处理
     * @param stWillAddItemData 待添加物品数据
     * @param iLeftAddNum 剩余要添加的数量
     * @param iAddNum 输出实际添加数量
     * @return 0成功，非0失败
     */
    virtual int AddItemWhenBagFull(const WillAddItemData& stWillAddItemData, int iLeftAddNum, int& iAddNum) = 0;
    
    /**
     * @brief 背包满时添加物品的特殊处理（物品对象版本）
     * @param pItem 物品对象
     * @param iLeftAddNum 剩余要添加的数量
     * @param iAddNum 输出实际添加数量
     * @return 0成功，非0失败
     */
    virtual int AddItemWhenBagFull(const NFGridItem* pItem, int iLeftAddNum, int& iAddNum) = 0;
protected:
    /**
     * @brief 添加前修正物品属性（绑定、品质等），与背包类型相关
     * @param stWillAddItemData 待添加物品数据
     * @param iBagType 背包页签类型
     * @return 0成功，非0失败
     */
    virtual int AddItemFix(WillAddItemData& stWillAddItemData, int iBagType) const;
    
    /**
     * @brief 添加前修正物品属性（物品对象版本）
     * @param stItem 物品对象
     * @param iBagType 背包页签类型
     * @return 0成功，非0失败
     */
    virtual int AddItemFix(NFGridItem& stItem, int iBagType) const;
    
    /**
     * @brief 计算添加结果：当未全部添加且 pAddedNum 为空时返回"页签满"错误码
     * @param stBagPageOp 页签操作器
     * @param iWantAddNum 期望添加数量
     * @param iRealAddNum 实际添加数量
     * @param pAddedNum 输出实际添加数量（=nullptr 必须全部添加，!=nullptr 尽可能添加）
     * @return 0成功，非0失败
     */
    virtual int CalcAddResult(NFBagPageOp& stBagPageOp, int iWantAddNum, int iRealAddNum, int* pAddedNum);
    
    /**
     * @brief 分配一个背包页签接口，已存在相同的时返回存在的
     * @param iBagType 背包页签类型
     * @param pInterface 输出接口指针
     * @return 0成功，非0失败
     */
    virtual int AllocInterfacePackage(int iBagType, NFBagPageInterfacePackage*& pInterface);
    
    /**
     * @brief 查找背包页签操作器
     * @param pBagPageInterface 背包页签接口
     * @return 页签操作器指针（可能为nullptr）
     */
    virtual NFBagPageOp* FindBagPageOp(NFBagPageInterface* pBagPageInterface);
    
    /**
     * @brief 创建背包页签操作器
     * @param pBagPageInterface 背包页签接口
     * @return 页签操作器指针（一定!=nullptr）
     */
    virtual NFBagPageOp* CreateBagPageOp(NFBagPageInterface* pBagPageInterface);
    
    /**
     * @brief 获取背包页签接口包装
     * @param pBagPage 背包页签
     * @return 接口包装指针（可能为nullptr）
     */
    virtual NFBagPageInterfacePackage* GetInterfacePackage(NFBagPage* pBagPage);
    
    /**
     * @brief 创建背包页签接口包装
     * @param pBagPage 背包页签
     * @return 接口包装指针（一定!=nullptr）
     */
    virtual NFBagPageInterfacePackage* CreateInterfacePackage(NFBagPage* pBagPage);

    /**
     * @brief 获取一个背包页签操作器，未找到时分配一个
     * @param pBagPageInterface 背包页签接口
     * @return 页签操作器指针（一定!=nullptr）
     */
    virtual NFBagPageOp* GetBagPageOp(NFBagPageInterface* pBagPageInterface);
protected:
    /** @brief 操作原因（影响 Item->BagType 路由与后续日志） */
    int m_enPackageOpReason;
    /** @brief 添加物品时的绑定策略 */
    enItemBindType m_enBindStatForAdd;
    /** @brief BagType -> BagPageOp 映射 */
    std::unordered_map<int, NFBagPageOp*> m_mapBagPageOp;

    /** @brief 当页签满时是否禁止转流至"背包满处理"逻辑 */
    bool m_bForbidAddWheFull;
    /** @brief 是否来源于邮件（部分逻辑可能需要区别） */
    bool m_bFromMail;
    /** @brief 删除物品时的过期截止时间（!=0 不删除过期<=此值的物品；=0 不检测过期） */
    uint32_t m_dwDelExpireUnixSec;

    /** @brief 物品实际操作个数 <物品ID, 操作数量>（commit时记录操作过的物品，数量可以是任何数） */
    std::unordered_map<int, int> m_opItemRec;
    /** @brief 物品实际变动个数 <物品ID, 变动数量>（只记录整个操作后变动了的物品数据，数量!=0） */
    std::unordered_map<int, int> m_itemChangeRec;

    /** @brief 缓存的 BagPage 接口包装（按 BagPage 维度复用） */
    std::vector<NFBagPageInterfacePackage*> m_vecCacheInterfacePackage;
    /** @brief 操作过程中的所有页签满错误码 */
    std::set<int> m_setTabFullErrCodes;

    /** @brief 本次参与操作的全部页签操作器 */
    std::vector<NFBagPageOp*> m_allBagPageOps;
    /** @brief 自己的背包页签操作器列表 */
    std::vector<NFBagPageOp*> m_vecPackage;
};